1 /*
2 * Copyright (C) 1998-2000 Semiotek Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted under the terms of either of the following
6 * Open Source licenses:
7 *
8 * The GNU General Public License, version 2, or any later version, as
9 * published by the Free Software Foundation
10 * (http://www.fsf.org/copyleft/gpl.html);
11 *
12 * or
13 *
14 * The Semiotek Public License (http://webmacro.org/LICENSE.)
15 *
16 * This software is provided "as is", with NO WARRANTY, not even the
17 * implied warranties of fitness to purpose, or merchantability. You
18 * assume all risks and liabilities associated with its use.
19 *
20 * See www.webmacro.org for more information on the WebMacro project.
21 */
22
23 package org.webmacro.util;
24
25 import org.webmacro.*;
26
27 import java.io.UnsupportedEncodingException;
28 import java.util.HashMap;
29 import java.util.Map;
30
31 /***
32 * A provider which dispenses Encoders, which are used for encoding
33 * Strings and caching the results.
34 * @since 0.96
35 * @author Michael Bayne
36 */
37
38 public class EncoderProvider implements Provider
39 {
40
41 private Map _encoders = new HashMap();
42 private Broker _broker;
43 private Settings _config;
44
45 /***
46 * The provider type for this provider. Use this when calling
47 * <code>Broker.getProvider()</code>.
48 */
49 public static final String TYPE = "encoder";
50
51 /***
52 * Return an array representing the types this provider serves up
53 */
54 public String getType ()
55 {
56 return TYPE;
57 }
58
59 /***
60 * Initialize this provider based on the specified config. Derived
61 * encoder provider implementations may override this method to obtain
62 * initialization parameters of their own devising, but they must be
63 * sure to call super.init() in their overridden methods.
64 */
65 public void init (Broker b, Settings config) throws InitException
66 {
67 _broker = b;
68 _config = config;
69 }
70
71 // Implementation note: the flush(), destroy() and get() methods are
72 // instance synchronized to ensure that if _encoders is cleared via the
73 // destroy() method and get() is called subsequently, we properly avoid
74 // referencing the null variable. We can't synchronize on _encoders
75 // because that becomes null and code that does this:
76 //
77 // if (_encoders != null) {
78 // synchronized (_encoders) {
79 //
80 // is not valid because the _encoders reference could become null
81 // in between those two statements.
82 //
83 // Additionally, the EncoderProvider is not invoked frequently enough
84 // to merit a more sophisticated synchronization approach (it is only
85 // called once per request when creating a FastWriter with which to
86 // output the response and not even that often because FastWriter
87 // instances are cached). Thus, we choose simplicity and robustness in
88 // this situation.
89
90 /***
91 * Clear any cache this provider may be maintaining.
92 */
93 public synchronized void flush ()
94 {
95 // clean out the encoder cache
96 _encoders.clear();
97 }
98
99 /***
100 * Close down this provider, freeing any allocated resources.
101 */
102 public synchronized void destroy ()
103 {
104 // clear out our reference to the encoder cache to allow it to be
105 // garbage collected
106 _encoders = null;
107 }
108
109 /***
110 * Get the object associated with the specified query.
111 */
112 public synchronized Object get (String encoding) throws ResourceException
113 {
114 Encoder encoder = null;
115
116 // make sure we're not inadvertently being called after we've
117 // already been destroy()ed
118 if (_encoders != null)
119 {
120 encoder = (Encoder) _encoders.get(encoding);
121
122 if (encoder == null)
123 {
124 try
125 {
126 // create and cache a new encoder instance for this
127 // encoding if one doesn't already exist in the cache
128 encoder = new Encoder(encoding);
129 encoder.init(_broker, _config);
130 _encoders.put(encoding, encoder);
131 }
132 catch (InitException e)
133 {
134 throw new ResourceException("Unable to initialize Encoder for "
135 + encoding + "; " + e);
136 }
137 catch (UnsupportedEncodingException uee)
138 {
139 throw new NotFoundException("Unsupported encoding: " +
140 uee.getMessage());
141 }
142 }
143 }
144 return encoder;
145 }
146 }